package com.hzw.code.security.filter;

import com.hzw.code.common.constant.BaseConstant;
import com.hzw.code.common.utils.ActionException;
import com.hzw.code.redis.dao.RedisDao;
import com.hzw.code.security.model.CustomUserDetails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author: 胡汉三
 * @date: 2020/5/26 10:20
 * @description: 对所有请求进行过滤
 * BasicAuthenticationFilter继承于OncePerRequestFilter==》确保在一次请求只通过一次filter，而不需要重复执行。
 */
public class PreAuthFilter extends OncePerRequestFilter {
    private RedisDao<String, CustomUserDetails> userRedis;
    private RedisDao<String,String> tokenRedis;
    public PreAuthFilter(RedisDao<String, CustomUserDetails> userRedis,
                         RedisDao<String,String> tokenRedis) {
        this.userRedis = userRedis;
        this.tokenRedis = tokenRedis;
    }

    /**
     * description: 从request的header部分读取Token
     *
     * @param request
     * @param response
     * @param chain
     * @return void
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        String tokenHeader = request.getHeader(BaseConstant.TOKEN_HEADER);
        // 如果请求头中没有Authorization信息则直接放行了
        if (tokenHeader == null || !tokenHeader.startsWith(BaseConstant.TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        // 如果请求头中有token，则进行解析，并且设置认证信息
        SecurityContextHolder.getContext().setAuthentication(getAuthentication(tokenHeader));
        chain.doFilter(request, response);
    }

    /**
     * description: 读取Token信息，创建UsernamePasswordAuthenticationToken对象
     *
     * @param tokenHeader
     * @return org.springframework.security.authentication.UsernamePasswordAuthenticationToken
     */
    private UsernamePasswordAuthenticationToken getAuthentication(String tokenHeader) {
        //解析Token时将“Bearer ”前缀去掉
        String token = tokenHeader.replace(BaseConstant.TOKEN_PREFIX, "");
        String userKey = tokenRedis.getValue(BaseConstant.TOKEN_KEY + token);
        if(StringUtils.isBlank(userKey)){
            throw new ActionException("token无效");
        }
        CustomUserDetails userDetails = userRedis.getValue(userKey);
        if (userDetails != null){
            // 刷新token
            tokenRedis.expire(BaseConstant.TOKEN_KEY + token,null);
            tokenRedis.expire(userKey,null);
            return new UsernamePasswordAuthenticationToken(userDetails.getUsername(), null, userDetails.getAuthorities());
        }
        return null;
    }
}
